from datetime import datetime, timedelta
from typing import Optional, List, Dict
from loguru import logger
import asyncio
from app.utils.logger import log_exception
from app.services.dahua_service import DahuaService
from app.services.hikvision_service import HikvisionService
from app.services.alarm_service import AlarmService

class DoorService:
    def __init__(self, dahua_service: DahuaService, hikvision_service: HikvisionService, alarm_service: AlarmService):
        self.dahua_service = dahua_service
        self.hikvision_service = hikvision_service
        self.alarm_service = alarm_service
        self.door_status = {}  # 存储门禁状态
        self.countdown_tasks: Dict[str, asyncio.Task] = {}  # 存储倒计时任务
        
    @log_exception
    async def process_access_request(self, door_id: str, face_record: dict, card_records: List[dict]) -> bool:
        """处理访问请求"""
        try:
            # 1. 验证人脸识别
            face_valid = await self.hikvision_service.validate_face_recognition(face_record)
            if not face_valid:
                logger.warning(f"人脸识别验证失败: {door_id}")
                return False
                
            # 2. 验证刷卡记录
            cards_valid = await self.dahua_service.validate_cards(card_records)
            if not cards_valid:
                logger.warning(f"刷卡验证失败: {door_id}")
                return False
                
            # 3. 验证时间间隔
            if not self._validate_time_interval(face_record, card_records):
                logger.warning(f"时间间隔验证失败: {door_id}")
                return False
                
            # 4. 开门
            await self.open_door(door_id)
            return True
            
        except Exception as e:
            logger.error(f"处理访问请求失败: {str(e)}")
            raise
            
    @log_exception
    async def open_door(self, door_id: str):
        """开门操作"""
        try:
            # 检查服务是否已初始化
            logger.debug(f"检查大华服务初始化状态: api_host={self.dahua_service.api_host}")
            if not self.dahua_service.api_host:
                error_msg = "大华服务未初始化"
                logger.error(error_msg)
                raise Exception(error_msg)
                
            # 调用大华平台的开门接口
            logger.debug(f"准备调用大华平台开门接口: door_id={door_id}")
            logger.debug(f"大华服务配置: api_host={self.dahua_service.api_host}, app_key={self.dahua_service.app_key}, app_secret={self.dahua_service.app_secret}")
            success = await self.dahua_service.control_door(door_id, "open")
            logger.debug(f"大华平台开门接口返回: success={success}")
            
            if success:
                self.door_status[door_id] = "open"
                # 启动倒计时
                await self._start_countdown(door_id)
                logger.info(f"门已开启，开始15分钟倒计时: {door_id}")
            else:
                error_msg = "开门操作失败"
                logger.error(f"{error_msg}: door_id={door_id}")
                raise Exception(error_msg)
        except Exception as e:
            error_msg = f"开门失败: {str(e)}"
            logger.error(f"{error_msg}, door_id={door_id}")
            raise Exception(error_msg)
            
    @log_exception
    async def close_door(self, door_id: str):
        """关门操作"""
        try:
            # 调用大华平台的关门接口
            success = await self.dahua_service.control_door(door_id, "close")
            if success:
                self.door_status[door_id] = "closed"
                # 取消倒计时
                await self._cancel_countdown(door_id)
                logger.info(f"门已关闭，取消倒计时: {door_id}")
            else:
                logger.error(f"关门操作失败: {door_id}")
                raise Exception("关门操作失败")
        except Exception as e:
            logger.error(f"关门失败: {str(e)}")
            raise
            
    @log_exception
    async def get_door_status(self, door_id: str) -> Optional[str]:
        """获取门的当前状态"""
        try:
            # 从大华平台获取实时状态
            status = await self.dahua_service.get_door_status(door_id)
            if status:
                # 更新本地状态缓存
                self.door_status[door_id] = status
                return status
            return self.door_status.get(door_id)
        except Exception as e:
            logger.error(f"获取门状态失败: {str(e)}")
            return None
            
    async def _start_countdown(self, door_id: str):
        """启动倒计时"""
        # 如果已存在倒计时任务，先取消它
        await self._cancel_countdown(door_id)
        
        # 创建新的倒计时任务
        self.countdown_tasks[door_id] = asyncio.create_task(
            self._countdown_timer(door_id)
        )
        
    async def _cancel_countdown(self, door_id: str):
        """取消倒计时"""
        if door_id in self.countdown_tasks:
            task = self.countdown_tasks[door_id]
            if not task.done():
                task.cancel()
                try:
                    await task
                except asyncio.CancelledError:
                    pass
            del self.countdown_tasks[door_id]
            
    async def _countdown_timer(self, door_id: str):
        """倒计时计时器"""
        try:
            # 等待15分钟
            await asyncio.sleep(15 * 60)  # 15分钟 = 15 * 60秒
            
            # 检查门的状态
            if self.door_status.get(door_id) == "open":
                logger.warning(f"门禁超时未关闭: {door_id}")
                # 触发报警
                await self.alarm_service.trigger_timeout_alarm(door_id)
                
        except asyncio.CancelledError:
            # 倒计时被取消（正常关门）
            logger.info(f"倒计时已取消: {door_id}")
            raise
        except Exception as e:
            logger.error(f"倒计时处理异常: {str(e)}")
            raise

    def _validate_time_interval(self, face_record: dict, card_records: List[dict]) -> bool:
        """验证人脸识别和刷卡时间间隔是否在1分钟内"""
        try:
            # 检查必要字段
            if "time" not in face_record:
                logger.warning("人脸识别记录缺少时间字段")
                return False
                
            for record in card_records:
                if "time" not in record:
                    logger.warning("刷卡记录缺少时间字段")
                    return False
            
            # 解析时间
            try:
                face_time = datetime.fromisoformat(face_record['time'])
                card_times = [datetime.fromisoformat(record['time']) for record in card_records]
            except ValueError as e:
                logger.error(f"时间格式解析失败: {str(e)}")
                return False
            
            # 获取最早和最晚的时间
            earliest_time = min([face_time] + card_times)
            latest_time = max([face_time] + card_times)
            
            # 验证时间间隔是否小于1分钟
            time_diff = latest_time - earliest_time
            is_valid = time_diff <= timedelta(minutes=1)
            
            if not is_valid:
                logger.warning(f"时间间隔超过1分钟: {time_diff.total_seconds()}秒")
                
            return is_valid
            
        except Exception as e:
            logger.error(f"验证时间间隔失败: {str(e)}")
            return False
